define(["knockout", "jquery", "ps"], function(ko, $) {
  var throttle = function(func, wait, options, ps) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
      previous = options.leading === false ? 0 : new Date().getTime();
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };

    var throttled = function() {
      var now = new Date().getTime();
      if (!previous && options.leading === false) previous = now;
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      if (remaining <= 0 || remaining > wait) {
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        timeout = setTimeout(later, remaining);
      }
      return result;
    };

    throttled.cancel = function() {
      clearTimeout(timeout);
      previous = 0;
      timeout = context = args = null;
    };

    return throttled;
  };

  function VirtualContainer(config) {
    this.onlyList = ko.observable(config.onlyList); //只进行列显示，否则考虑行显示，需要项的宽度
    this.itemHeight = ko.observable(config.itemHeight);
    this.itemWidth = ko.observable(config.itemWidth);
    this.containerHeight = ko.observable(config.containerHeight);
    this.containerWidth = ko.observable(config.containerWidth);
    if (ko.isObservableArray(config.contents)) {
      this.members = config.contents; //总成员数量
    } else {
      this.members = ko.observableArray(config.contents); //总成员数量
    }
    this.contentTop = ko.observable(0);
    this.containerScrollTop = ko.observable(0);
    this.$container = null;
    //一行显示的数量
    this.lineItemCount = ko.computed(function() {
      //如果是列显示，一行自然只有一个
      if (this.onlyList()) {
        return 1;
      } else {
        return Math.floor(this.containerWidth() / this.itemWidth());
      }
    }, this);
    //行的数量
    this.lineCount = ko.computed(function() {
      return Math.ceil(this.members().length / this.lineItemCount());
    }, this);
    //额外显示的子项数量,多两行的数量
    this.extraItemNumber = ko.computed(function() {
      if (this.onlyList()) {
        return 2; //1*2
      } else {
        return this.lineItemCount() * 2;
      }
    }, this);

    //实际显示成员数量
    this.displayMembers = ko.computed(function() {
      if (this.onlyList()) {
        return this.getVirtualList();
      } else {
        return this.getVirtualPanel();
      }
    }, this);

    this.containerStyle = ko.pureComputed(function() {
      return {
        height: this.containerHeight() + "px",
        width: this.containerWidth() + "px"
      };
    }, this);

    this.holderStyle = ko.pureComputed(function() {
      var style = {};
      if (this.onlyList()) {
        style = {
          height: this.itemHeight() * this.members().length + "px"
        };
      } else {
        style = {
          height: this.itemHeight() * this.lineCount() + "px"
        };
      }
      return style;
    }, this);

    this.contentStyle = ko.pureComputed(function() {
      return {
        top: this.contentTop() + "px"
      };
    }, this);
  }

  //获取虚拟列表
  VirtualContainer.prototype.getVirtualList = function() {
    var extraItemNumber = this.extraItemNumber();
    var containerScrollTop = this.containerScrollTop();
    var itemHeight = this.itemHeight();
    var containerHeight = this.containerHeight();
    var members = this.members();

    var firstIndex = Math.floor(containerScrollTop / itemHeight);

    var lastIndex = firstIndex + Math.ceil(containerHeight / itemHeight);

    firstIndex = Math.max(firstIndex - extraItemNumber, 0);
    lastIndex = Math.min(lastIndex + extraItemNumber, members.length);

    var arr = [];
    for (var i = firstIndex; i < lastIndex; i++) {
      arr.push(members[i]);
    }

    this.contentTop(firstIndex * itemHeight);

    return arr;
  };

  //获取虚拟界面
  VirtualContainer.prototype.getVirtualPanel = function() {
    var extraItemNumber = this.extraItemNumber();
    var containerScrollTop = this.containerScrollTop();
    var itemHeight = this.itemHeight();
    var containerHeight = this.containerHeight();
    var lineItemCount = this.lineItemCount();
    var members = this.members();

    var firstIndex =
      Math.floor(containerScrollTop / itemHeight) * lineItemCount;

    var lastIndex =
      firstIndex + Math.ceil(containerHeight / itemHeight) * lineItemCount;

    firstIndex = Math.max(firstIndex - extraItemNumber, 0);
    lastIndex = Math.min(lastIndex + extraItemNumber, members.length);

    //根据index获取要显示的项
    var arr = [];
    for (var i = firstIndex; i < lastIndex; i++) {
      arr.push(members[i]);
    }

    this.contentTop(Math.floor(containerScrollTop / itemHeight) * itemHeight);

    return arr;
  };
  VirtualContainer.prototype.attached = function(view, parent, bindingContext) {
    this.$container = $(view);
    this._handleContainerScrollThrottle = throttle(function() {
      this.containerScrollTop(this.$container.prop("scrollTop"));
    }, 30);
    $(this.$container).perfectScrollbar();
  };

  VirtualContainer.prototype.handleContainerScroll = function() {
    this._handleContainerScrollThrottle();
  };
  VirtualContainer.prototype.updateConfig = function(config) {
    if (config === null || config === undefined) {
      config = {};
    }
    $(this.$container).perfectScrollbar("update");
  };
  VirtualContainer.prototype._handleContainerScrollThrottle = null;
  return VirtualContainer;
});
